<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.5.0 / SVN信息: $Id: class.JCAT_DB.php 1603 2009-03-31 15:35:42Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/
namespace JCAT ;




/**
 * DB类 为 整个 DB包 提供一个易用的 外观接口，从而不需了解 DB包内部 的细节
 *
 * @author		alee
 * @access		public
 */
class DB
{


	/**
	 * 
	 * @access	public
	 * @param	$sFactoryClassName=''	string	具体对象工厂的类名
	 * @return	void
	 */
	public function DB( $sFactoryClassName='' ) 
	{
		if($sFactoryClassName=='')
			$sFactoryClassName = self::$sPreferredFactory ;
		
		ASSERT::ASSERT_STRING($sFactoryClassName) ;
				
		//ASSERT::ASSERT_( GlobalFunc::IsKindOf($sFactoryClassName,''), Language::SentenceEx('','JCAT',null)"参数 " ) ;
		ASSERT::ASSERT_ISTHESE($sFactoryClassName,array('JCAT\DBAbstractFactory'),Language::SentenceEx('参数 $sFactoryClassName="%s" 必须为 DBAbstractFactory 的派生类类名','JCAT',null,$sFactoryClassName)) ;
	
		$this->aFactory = new $sFactoryClassName() ;
		$this->aConnect = $this->aFactory->CreateConnect() ;
	}

	/**
	 * 使用首选信息窗件一个默认的 对象
	 * 
	 * @access	public
	 * @param	$bGlobalIns=''	bool	全局实例
	 * @param	$bConnect=''	bool	连接到数据库
	 * @return	DB
	 */
	static public function CreateDefaultInstance( $bGlobalIns=true, $bConnect=true )
	{
		if( $bGlobalIns and self::$aGlobalDefaultInstance )
			return self::$aGlobalDefaultInstance ;
		
		// 创建
		$aDB = new DB() ;
		
		// 连接
		if($bConnect)
		{
			$aDB->Connect(self::$sPreferredDBServer,self::$sPreferredDBUser,self::$sPreferredDBPassword,false) ;
			if( !empty(self::$sPreferredDBName) )
				$aDB->SelectDB(self::$sPreferredDBName) ;
		}
		
		// 设置全局对象
		if($bGlobalIns)
			self::$aGlobalDefaultInstance = $aDB ;
		
		// 返回
		return $aDB ;
	}

	/**
	 * 返回具体工厂
	 * 
	 * @access	public
	 * @return	IDBAbstractFactory
	 */
	public function GetFactory(  ) 
	{ return $this->aFactory ; }




	/**
	 * 连接到数据库服务器
	 * 
	 * @access	public
	 * @param	$sHost='localhost'	string	数据库主机名
	 * @param	$sUser=''			string	用户名，缺省使用当前用户（Linux）
	 * @param	$sPassword=''		string	密码
	 * @param	$bPersistent=true	bool	持久连接
	 * @return	bool
	 */
	public function Connect(  $sHost='localhost',  $sUser=null,  $sPassword='',  $bPersistent=true ) 
	{ return $this->aConnect->Connect($sHost,  $sUser,  $sPassword,  $bPersistent) ; }




	/**
	 * 断开连接
	 * 
	 * @access	public
	 * @return	bool
	 */
	public function Disconnect(  ) 
	{ return $this->aConnect->Disconnect() ; }



	/**
	 * 设置一个连接对象
	 * 
	 * @access	public
	 * @param	$aConnect	DBConnect	DBConnect	连接对象
	 * @return	
	 */
	public function SetConnect( DBConnect $aConnect ) 
	{
		// Todo Samething ... ...
		// ... ...
	}



	/**
	 * 返回连接对象
	 * 
	 * @access	public
	 * @return	DBConnect
	 */
	public function GetConnect() 
	{ return $this->aConnect ; }







	/**
	 * 选择一个数据库（不是所有 类型的数据库 都可用，例如 SQLite 无效）
	 * 
	 * @access	public
	 * @param	$sDBName	string	数据库名
	 * @return	old_value
	 */
	public function SelectDB( $sDBName ) 
	{
		ASSERT::ASSERT_STRING($sDBName) ;
		
		return $this->aConnect->SelectDB($sDBName) ;
	}



	/**
	 * 执行 SQL 语句
	 * 
	 * @access	public
	 * @param	$SQL		DBGenericTypes::$SQL	SQL语句
	 * @param	$sDB=null	string						指定数据库。如果为空'' ，则使用当前数据库( SelectDB() )
	 * @return	bool, resource
	 */
	public function Query(  $SQL,  $sDB='' ) 
	{ return $this->aConnect->Query($SQL,$sDB) ; }



	/**
	 * 插入数据
	 * 
	 * @access	public
	 * @param	$sTable				string	用于操作的数据表
	 * @param	$bReplace=false		bool	Repalce 或 Insert 
	 * @return	bool
	 */
	public function Insert( $sTableName, array $arrData ) 
	{
		$aSQL = $this->aFactory->CreateSQLInsert($sTableName) ;
		$aSQL->SetData($arrData) ;//fo($arrData) ;
		return $this->Query($aSQL)? true: false ;
	}

	/**
	 * 删除记录
	 * 
	 * @access	public
	 * @param	$Tables			DBGenericTypes::$TableList		数据表
	 * @param	$Where=''		string,DBSubSQLWhere			Where 子句
	 * @return	bool
	 */
	public function Delete( $Tables, $Where='' ) 
	{
		ASSERT::ASSERT_ISTHESE($Where,array('string','JCAT\DBSubSQLWhere')) ;
		
		// 创建 Delete
		$aSQL = $this->aFactory->CreateSQLDelete($Tables) ;
		
		// 设置 Where 子句
		if( is_string($Where) )
		{
			if( !preg_match('/^\s*where/si',$Where) )
			{
				$Where = 'WHERE '.$Where ;
			}

			$aSQL->SetStringSubSQLWhere($Where) ;
		}

		else if( GlobalFunc::IsKindOf($Where,'DBSubSQLWhere') )
		{
			$aSQL->SetSubSQLWhere($Where) ;
		}

		else
		{
			ASSERT::ASSERT_(false,'!?') ;
		}
			
		return $this->Query($aSQL) ;
	}



	/**
	 * 执行 Update
	 * 
	 * @access	public
	 * @param	$Tables			DBGenericTypes::$TableList		数据表
	 * @param	$arrData		array								数据值对
	 * @param	$Where=''		string,DBSubSQLWhere			Where 子句
	 * @return	bool
	 */
	public function Update( $Tables, array $arrData,  $Where='' ) 
	{
		ASSERT::ASSERT_ISTHESE($Where,array('string','JCAT\DBSubSQLWhere')) ;
		
		// 创建 Update
		$aUpdate = $this->aFactory->CreateSQLUpdate($Tables) ;
		
		// 设置 Where 子句
		if( is_string($Where) )
		{
			$aUpdate->SetStringSubSQLWhere('Where '.$Where) ;
		}
		else if( GlobalFunc::IsKindOf($Where,'DBSubSQLWhere') )
		{
			$aUpdate->SetSubSQLWhere($Where) ;
		}
		else
		{
			ASSERT::ASSERT_(false,'!?') ;
		}
		
		// 设置数据
		$aUpdate->SetData($arrData) ;
		
		// 执行并返回结果
		return $this->Query($aUpdate) ;
	}


	const RETURN_SQL = 'SQL' ;
	const RETURN_HANDLE = 'Result' ;
	const RETURN_RECORDSET = 'RecordSet' ;
	const RETURN_ARRAY = 'Array' ;

	/**
	 * 执行数据表查询
	 * 可依据参数 $sReturn 返回不同类型的查询结果： handle,DBRecordSet,DBSQLSelect
	 * 
	 * @access	public
	 * @param	$Tables					DBGenericTypes::$TableList			数据表
	 * @param	$Where=''				string,DBSubSQLWhere				Where 子句
	 * @param	$ReturnColums='*'		DBGenericTypes::$ReturnColumnList	返回字段
	 * @param	$sReturn='RecordSet'	string									返回类型：'Result','RecordSet','SQL'
	 * @return	DBRecordSet
	 */
	public function Select(  $Tables,  $Where='',  $ReturnColums='*', $sReturn=self::RETURN_RECORDSET ) 
	{
		ASSERT::ASSERT_ISTHESE($Where,array('string','JCAT\DBSubSQLWhere')) ;
		ASSERT::ASSERT_STRING($sReturn) ;
		
		// 创建 Update
		$aSelect = $this->aFactory->CreateSQLSelect($Tables) ;
		
		// 设置 Where 子句
		if( is_string($Where) )
		{
			$Where = trim($Where) ;
			if($Where)
			{
				if( !preg_match('/^where/i',$Where) )
				{
					$Where = 'WHERE '.$Where ;
				}
				
				$aSelect->SetStringSubSQLWhere($Where) ;
			}
		}
		else if( GlobalFunc::IsKindOf($Where,'DBSubSQLWhere') )
		{
			$aSelect->SetSubSQLWhere($Where) ;
		}
		else
		{
			ASSERT::ASSERT_(false,'!?') ;
		}
		
		// 原始字串格式
		if( is_string($ReturnColums) and preg_match("/[\(\,\"'\`]/",$ReturnColums) )
		{
			$aSelect->SetStringSubSQLReturnColumnList($ReturnColums) ;
		}
		
		// 创建 return column 对象
		else 
		{
			$aSelect->SetSubSQLReturnColumnList( DBGenericTypes::TransReturnColumnList($this->GetFactory(),$ReturnColums) ) ;
		}

		$sExceptionMsg=Language::SentenceEx("无效的返回类型：“%s”。有效的返回类型为：'Result'(resource handle),'RecordSet','SQL'",'JCAT',null,$sReturn) ;
		$sReturn = strtolower($sReturn) ;
		switch( $sReturn )
		{
			case 'result' :
				return $this->Query($aSelect) ;
				break ;
			
			case 'recordset' :
				$aRecordSet = $this->aFactory->CreateRecordSet($this->GetConnect()) ;
				$aRecordSet->Query($aSelect) ;
				return $aRecordSet ;
				break ;
			
			case 'sql' :
				return $aSelect ;
				break ;
			
			default :
				throw new Exception( $sExceptionMsg, Exception::MakeExceptionCode(__CLASS__,1) ) ;
				break ;
		}
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$Tables		What's this Parameter ?
	 * @param	$Where=null		What's this Parameter ?
	 * @param	$Clms='*'		What's this Parameter ?
	 * @param	$nCacheSecs=0		What's this Parameter ?
	 * @return	DBRecordSetCache
	 */
	public function SelectCache(  $Tables,  $Where=null,  $Clms='*',  $nCacheSecs=0 ) 
	{
		// Todo Samething ... ...
		// ... ...
	}



	/**
	 * 只返回一行记录
	 * 
	 * @access	public
	 * @param	$Tables					DBGenericTypes::$TableList			数据表
	 * @param	$Where=''				string,DBSubSQLWhere				Where 子句
	 * @param	$ReturnColums='*'		DBGenericTypes::$ReturnColumnList	返回字段
	 * @param	$sReturn='Array'		string									返回类型：'Result','RecordSet','SQL','Array'
	 * @return	handle,DBRecordSet,DBSQLSelect,array
	 */
	public function SelectOneRow(  $Tables,  $Where='',  $Clms='*', $sReturn=self::RETURN_ARRAY ) 
	{
		$aSelect = $this->Select($Tables,$Where,$Clms,'SQL') ;
		ASSERT::ASSERT_INSTANCE($aSelect,'JCAT\DBSQLSelect') ;
		
		$aSelect->SetLimit(1,0) ;
		
		$sExceptionMsg=Language::SentenceEx("无效的返回类型：“%s”。有效的返回类型为：'Result'(resource handle),'RecordSet','SQL'",'JCAT',null,$sReturn) ;
		$sReturn = strtolower($sReturn) ;
		switch( $sReturn )
		{
			case 'result' :
				return $this->Query($aUpdate) ;
				break ;
			
			case 'recordset' :
				$aRecordSet = $this->aFactory->CreateRecordSet($this->GetConnect()) ;
				$aRecordSet->Query($aSelect) ;
				return $aRecordSet ;
				break ;
			
			case 'array' :
				$aRecordSet = $this->aFactory->CreateRecordSet($this->GetConnect()) ;
				$aRecordSet->Query($aSelect) ;
				if( $aRecordSet->GetCount() )
					return $aRecordSet->GetRow(0) ;
				else
					return null ;
				break ;
			
			case 'sql' :
				return $aSelect ;
				break ;
			
			default :
				throw new Exception( $sExceptionMsg, Exception::MakeExceptionCode(__CLASS__,1) ) ;
				break ;
		}
		
	}



	/**
	 * 返回符合条件的第一行的指定列
	 * 
	 * @access	public
	 * @param	$Tables				DBGenericTypes::$TableList			数据表
	 * @param	$sColumnName		string									返回字段名称
	 * @param	$Where=''			string,DBSubSQLWhere				Where 子句
	 * @return	string,null
	 */
	public function SelectOneField(  $Tables,  $sColumnName,  $Where='' ) 
	{
		$RetClm = $this->aFactory->CreateReturnColumn($sColumnName) ;
		ASSERT::ASSERT_INSTANCE($RetClm,'JCAT\DBReturnColumn') ;

		$aSelect = $this->Select($Tables,$Where,$sColumnName,'SQL') ;
		ASSERT::ASSERT_INSTANCE($aSelect,'JCAT\DBSQLSelect') ;
		
		$aSelect->SetLimit(1,0) ;
		
		$aRecordSet = $this->aFactory->CreateRecordSet($this->GetConnect()) ;
		$aRecordSet->Query($aSelect) ;
		
		if( $aRecordSet->GetCount() )
		{
			$arrRow = $aRecordSet->GetRow(0) ;
			return array_pop($arrRow) ;
		}
		else
		{
			return null ;
		}
	}



	/**
	 * 返回符合条件的行数
	 * 
	 * @access	public
	 * @param	$Tables					DBGenericTypes::$TableList			数据表
	 * @param	$Where=''				string,DBSubSQLWhere				Where 子句
	 * @return	int
	 */
	public function GetCount( $Tables, $Where='' ) 
	{
		$aRecordSet = $this->Select($Tables,$Where,'*','RecordSet') ;
		ASSERT::ASSERT_INSTANCE($aRecordSet,'JCAT\DBRecordSet') ;
		
		return $aRecordSet->GetCount() ;
	}



	/**
	 * 返回刚刚插入的行的主键值
	 * 
	 * @access	public
	 * @return	int
	 */
	public function GetInsertID() 
	{ return $this->aConnect->GetInsertID() ; }



	/**
	 * 增加
	 * 
	 * @access	public
	 * @param	$Tables			DBGenericTypes::$TableList		数据表
	 * @param	$Column			DBGenericTypes::$Column		字段名称
	 * @param	$Where=''		string,DBSubSQLWhere			Where 子句
	 * @param	$nStep=1		int									变化幅度
	 * @return	
	 */
	public function Increase(  $Tables,  $sClmName,  $Where='',  $nStep=1 ) 
	{ return $this->_InDecrease($Tables,  $Column, '+',  $Where,  $nStep) ; }



	/**
	 * 减少
	 * 
	 * @access	public
	 * @param	$Tables			DBGenericTypes::$TableList		数据表
	 * @param	$Column			DBGenericTypes::$Column		字段名称
	 * @param	$Where=''		string,DBSubSQLWhere			Where 子句
	 * @param	$nStep=1		int									变化幅度
	 * @return	bool
	 */
	public function Decrease(  $Tables,  $Column,  $Where='',  $nStep=1 ) 
	{ return $this->_InDecrease($Tables,  $Column, '-',  $Where,  $nStep) ; }

	/**
	 * 递减
	 * 
	 * @access	public
	 * @param	$Tables			DBGenericTypes::$TableList		数据表
	 * @param	$Column			DBGenericTypes::$Column		字段名称
	 * @param	$sOperator		string								操作符 '+' 或 '-'
	 * @param	$Where=''		string,DBSubSQLWhere			Where 子句
	 * @param	$nStep=1		int									变化幅度
	 * @return	bool
	 */
	private function _InDecrease(  $Tables,  $Column, $sOperator,  $Where='',  $nStep=1 ) 
	{
		$aColumn = DBGenericTypes::TransColumn($this->aFactory,$Column) ;		
		ASSERT::ASSERT_ISTHESE($Where,array('string','JCAT\DBSubSQLWhere')) ;
		ASSERT::ASSERT_INT($nStep) ;
		ASSERT::ASSERT_STRING($sOperator) ;
		
		$aUpdate = $this->aFactory->CreateSQLUpdate($Tables) ;
		
		// 设置 Where 子句
		if( is_string($Where) )
			$aUpdate->SetStringSubSQLWhere($Where) ;
		else if( GlobalFunc::IsKindOf($Where,'DBSubSQLWhere') )
			$aUpdate->SetSubSQLWhere($Where) ;
		else
			ASSERT::ASSERT_(false,'!?') ;
		
		// 
		$sColumnName = $aColumn->MakeSQL() ;
		$aValue = $this->aFactory->CreateOriginValue("{$sColumnName} = {$sColumnName} {$sOperator} $nStep") ;
		$aUpdate->SetData($aColumn,$aValue) ;
		
		return $this->Query($aUpdate) ;
	}







	/**
	 * 返回数据库的错误信息
	 * 
	 * @access	public
	 * @return	string
	 */
	public function GetError(  ) 
	{
		return $this->aConnect->GetError() ;
	}



	/**
	 * 返回数据库的错误代码
	 * 
	 * @access	public
	 * @return	int
	 */
	public function GetErrorCode(  ) 
	{
		return (int)$this->aConnect->GetError(true) ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$bPrint=true		What's this Parameter ?
	 * @return	
	 */
	public function DebugInfo(  $bPrint=true ) 
	{
		// Todo Samething ... ...
		// ... ...
	}


	/**
	 * 创建并返回一个 DBExpression 对象
	 *
	 * @access	public
	 * @param	$sExpression	string
	 * @static
	 * @return	DBExpression
	 */
	static public function E($sExpression)
	{
		return new DBExpression($sExpression) ;
	}

	/**
	 * 创建并返回一个 DBColumn 对象
	 *
	 * @access	public
	 * @param	$sColumn		string
	 * @param	$sTable=null	string
	 * @static
	 * @return	DBColumn
	 */
	static public function C($sColumn,$sTable='')
	{
		return new DBColumn(null,$sColumn,$sTable) ;
	}

	// 属性 ///////////////////////////////////////////////////////////////////////////////

	/**
	 * 首选 工厂类
	 * 
	 * @access	public
	 * @var		string
	 * @static
	 */
	static public $sPreferredFactory = 'DBFactoryMySQL41' ;

	/**
	 * 首选 数据库 服务器
	 * 
	 * @access	public
	 * @var		string
	 * @static
	 */
	static public $sPreferredDBServer = 'localhost' ;

	/**
	 * 首选 数据库 库名
	 * 
	 * @access	public
	 * @var		string
	 * @static
	 */
	static public $sPreferredDBName = '' ;

	/**
	 * 首选 数据库 用户名
	 * 
	 * @access	public
	 * @var		string
	 * @static
	 */
	static public $sPreferredDBUser = 'root' ;

	/**
	 * 首选 数据库 用户密码
	 * 
	 * @access	public
	 * @var		string
	 * @static
	 */
	static public $sPreferredDBPassword = '' ;

	/**
	 * 首选 数据库 用户密码
	 * 
	 * @access	private
	 * @var		DB
	 * @static
	 */
	static private $aGlobalDefaultInstance ;
	
	/**
	 * 具体工厂
	 * 
	 * @access	public
	 * @var		DBAbstractFactory
	 * @static
	 */
	private $aFactory = null ;
	
	/**
	 * 数据库连接对象
	 * 
	 * @access	public
	 * @var		DBConnect
	 * @static
	 */
	private $aConnect = null ;


}
/*macro_exception_code:1*/
?>